# -*- coding: utf-8 -*-
import hashlib
import json
from datetime import datetime
from collections import OrderedDict

import requests
from django.conf import settings

from common.bankcard import db as bank_db
from common.bankcard.model import BANK_DCT
from common.mch import handler as mch_handler
from common.mch.db import get_account
from common.timer import TIMER_EVENT_TYPE
from common.timer.handler import submit_notify_event
from common.utils import track_logging
from common.utils import tz
from common.utils.exceptions import ParamError
from common.withdraw import db as withdraw_db
from common.withdraw.model import WITHDRAW_ORDER_STATUS

_LOGGER = track_logging.getLogger('withdraw')

APP_CONF = {
    'KS': {
        'API_KEY': '61372189-1026-23ec-10ee-0f6a0c429dcd',
        'GATEWAY': 'https://banktrans.608pay.com/bank-service/withdraw?time={}&sign={}',
        'QUERY_GATEWAY': 'https://banktrans.608pay.com/bank-service/queryOrder?orderID={}&merchantCode={}&token={}',
        'INFO': '正式环境',
    },
}


def _get_api_key(app_id):
    return APP_CONF[app_id]['API_KEY']


def _get_gateway(app_id):
    return APP_CONF[app_id]['GATEWAY']


def _get_query_gateway(app_id):
    return APP_CONF[app_id]['QUERY_GATEWAY']


# md5(request_body + time + token)
def generate_sign(parms, ts, key):
    """  生成下单签名 """
    s = '{}{}{}'.format(parms, ts, key)
    m = hashlib.md5()
    m.update(s)
    sign = m.hexdigest().lower()
    _LOGGER.info(u'group_withdraw origin string: %s, sign:%s', s, sign)
    return sign


def create_order(order, channel):
    try:
        app_id = channel.appid
        api_key = _get_api_key(app_id)
        mch = get_account(order.mch_id)
        info = {
            "user_id": str(order.user_id),
            "device_ip": order.client_ip or '127.0.0.1',
            "device_id": 'D3K9K78J4',
            "name": order.pay_account_username,
            "bank_card": order.pay_account_num,
            "bank_code": BANK_DCT[order.pay_account_bank],
            "tel": "15550019596",
            "device_type": "android",
        }
        parms = OrderedDict((
            ("merchant_id", app_id),
            ("order_id", '_'.join([str(mch.name), str(order.id)])),
            ("notify_url", settings.GROUP_WITHDRAW_NOTIFY_URL + app_id),
            ("bill_price", '%.2f' % float(order.amount)),
            ("extra", "charge"),
            ("info", info),
        ))
        parms = json.dumps(parms, separators=(',', ':'))
        ts = tz.now_ts()
        sign = generate_sign(parms, ts, api_key)
        # 先设置为三方未知状态
        order.status = WITHDRAW_ORDER_STATUS.THIRD_UNKNOWN
        order.third_type = channel.id
        order.save()
        url = _get_gateway(app_id).format(ts, sign)
        _LOGGER.info('group_withdraw create data: %s, %s', parms, url)
        headers = {'Content-type': 'application/json'}
        response = requests.post(url, headers=headers, data=parms, timeout=5)
        _LOGGER.info('group_withdraw create rsp: %s, %s', response.text, order.id)
        data = json.loads(response.text)
        third_id = data.get('flashid', None)
        status = data.get('status', None)
        if status == 10000 and third_id:
            order.status = WITHDRAW_ORDER_STATUS.THIRD
            order.third_id = str(third_id)
            order.extra_info = response.content
            order.save()
            return True
        else:
            order.detail = data.get('error', '')
            order.status = WITHDRAW_ORDER_STATUS.THIRD_FAIL
            order.extra_info = response.content
            order.save()
            return False
    except Exception, e:
        _LOGGER.info('group_withdraw create order fail: %s, %s', e, order.id)
        return False


def verify_notify_sign(params, json_body, key):
    sign = params['sign']
    params.pop('sign')
    s = '{}{}{}'.format(json_body, params['time'], key)
    m = hashlib.md5()
    m.update(s)
    calculated_sign = m.hexdigest().lower()
    if sign != calculated_sign:
        _LOGGER.info("group_withdraw sign: %s, calculated sign: %s", sign, calculated_sign)
        raise ParamError('sign not pass, data: %s' % params)


def check_notify_sign(request, app_id):
    api_key = _get_api_key(app_id)
    data = dict(request.GET.iteritems())
    _LOGGER.info("group_withdraw notify data: %s", data)
    _LOGGER.info("group_withdraw notify body: %s", request.body)
    verify_notify_sign(data, request.body, api_key)
    data = json.loads(request.body)
    _LOGGER.info("group_withdraw notify body data: %s", data)
    pay_id = int(data['merchant_order_id'].split('_')[1])
    if not pay_id:
        _LOGGER.error("group_withdraw fatal error, out_trade_no not exists, data: %s", data)
        raise ParamError('group_withdraw event does not contain pay ID')
    order = withdraw_db.get_order(pay_id)
    if not order or order.status != WITHDRAW_ORDER_STATUS.THIRD:
        _LOGGER.info('group_withdraw notify order not valid: %s ', pay_id)
        raise ParamError('group_withdraw event order not valid: %s' % pay_id)

    if data['status'] != 10000:
        order.status = WITHDRAW_ORDER_STATUS.THIRD_FAIL
        order.extra_info = request.body
        order.third_notify_at = datetime.utcnow()
        order.save()
        return
    order.status = WITHDRAW_ORDER_STATUS.DONE
    order.extra_info = request.body
    order.third_notify_at = datetime.utcnow()
    order.save()
    _LOGGER.info("group_withdraw success mch_id: %s, order_id: %s", order.mch_id, order.id)
    notify_success, _ = mch_handler.notify_mch_withdraw(order)
    if not notify_success:
        submit_notify_event(order, TIMER_EVENT_TYPE.MCH_WITHDRAW_NOTIFY)


def query_order(app_id, pay_id):
    parms = {
        "merchantCode": app_id,
        "orderID": app_id + '_' + str(pay_id),
    }
    api_key = _get_api_key(app_id)
    url = _get_query_gateway(app_id).format(parms['orderID'], parms['merchantCode'], api_key[-4:])
    response = requests.get(url)
    _LOGGER.info('group_withdraw query rsp, %s', response.text)
    if response.status_code != 200:
        return
    order = withdraw_db.get_order(pay_id)
    data = json.loads(response.text)
    if str(data['TradeState']) != '2':
        return
    order.status = WITHDRAW_ORDER_STATUS.DONE
    order.extra_info = response.text
    order.save()
    if data.get('accountNumber'):
        bank_db.update_real_balance(data['accountNumber'], data['cardBalance'])
    _LOGGER.info("group_withdraw success mch_id: %s, order_id: %s", order.mch_id, order.id)
    notify_success, _ = mch_handler.notify_mch_withdraw(order)
    if not notify_success:
        submit_notify_event(order, TIMER_EVENT_TYPE.MCH_WITHDRAW_NOTIFY)
